package org.springframework.boot;

import org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor;
import org.springframework.boot.context.event.EventPublishingRunListener;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.env.EnvironmentPostProcessorApplicationListener;
import org.springframework.boot.logging.DeferredLogs;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.SpringFactoriesLoader;

import java.util.List;

public class Step5 {
    public static void main(String[] args) {
        /**
         * 流程：这里添加一个监听器。在run的第五步后，通过发布事件的EventPublishingRunListener发布相关的事件，
         * 触发下面这个监听器，去读取配置文件的EnvironmentPostProcessor，增加环境变量的源。
         * 当然，下面这个EnvironmentPostProcessorApplicationListener其实也是配置文件里读的，这里直接手动
         * 添加演示其功能
         */
        SpringApplication app = new SpringApplication();
        app.addListeners(new EnvironmentPostProcessorApplicationListener());

        EventPublishingRunListener publisher = new EventPublishingRunListener(app, args);
        ApplicationEnvironment env = new ApplicationEnvironment();
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>> 增强前");
        for (PropertySource<?> ps : env.getPropertySources()) {
            System.out.println(ps);
        }


        //发布environmentPrepared的事件，会触发前面的监听器。所以可以看到PropertySource增多了
        publisher.environmentPrepared(new DefaultBootstrapContext(), env);
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>> 增强后");
        for (PropertySource<?> ps : env.getPropertySources()) {
            System.out.println(ps);
        }


    }

    public static void test2(){
        /**
         * 很多类都是配置在配置文件里。比如读取环境变量的接口EnvironmentPostProcessor与其对应的实现类
         * 都有在spring.factories中配置，而不是写死在java代码中。好处也很明显，拓展性更强。通过下面的API
         * 可以读取到spring.factories的内容
         */
        List<String> names = SpringFactoriesLoader.loadFactoryNames(EnvironmentPostProcessor.class, Step5.class.getClassLoader());
        for (String name : names) {
            System.out.println(name);
        }
    }


    public static void test(){
        SpringApplication app = new SpringApplication();
        ApplicationEnvironment env = new ApplicationEnvironment();

        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>> 增强前");
        for (PropertySource<?> ps : env.getPropertySources()) {
            System.out.println(ps);
        }

        /**
         * 后处理器用作为ApplicationEnvironment做拓展。ConfigDataEnvironmentPostProcessor的作用
         * 即是读取配置文件application.properties的键值。当然，这些后处理器都是配置在配置文件当中，有spring
         * 在启动的时候去读取这些类，而不是硬编码。这里只是为了演示其作用。想看这些类配置的地方，使用右键菜单的
         * find Usage即可
         */
        System.out.println(env.getProperty("server.port"));
        ConfigDataEnvironmentPostProcessor postProcessor1 = new ConfigDataEnvironmentPostProcessor(new DeferredLogs(), new DefaultBootstrapContext());
        postProcessor1.postProcessEnvironment(env, app);
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>> 增强后");
        for (PropertySource<?> ps : env.getPropertySources()) {
            System.out.println(ps);
        }
        System.out.println(env.getProperty("server.port"));
    }
}
